/*
 * Copyright (C) 2020/12/13
 * by zhuyk
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.fred.colorpicker

import android.content.Context
import android.graphics.*
import android.os.Build
import android.util.AttributeSet
import android.util.Log
import android.view.View
import androidx.annotation.ColorInt
import androidx.annotation.RequiresApi
import kotlin.math.max
import kotlin.math.min

/**
 * 彩色 - 灰度 选择条
 */
class GraySeekBarView:View {

    private val externalHeight = context.dip(5F)
    private val innerHeight = context.dip(4F)
    private val externalRect by lazy {
        RectF()
    }
    private val innerRect by lazy {
        RectF()
    }
    private val externalPaint by lazy {
        Paint(Paint.ANTI_ALIAS_FLAG).apply {
            color = Color.WHITE
            style = Paint.Style.FILL
        }
    }
    private val innerPaint by lazy {
        Paint(Paint.ANTI_ALIAS_FLAG).apply {
            color = Color.BLUE
            style = Paint.Style.FILL
        }
    }
    private val mHSV by lazy {
        FloatArray(3)
    }
    private var colorBrightness = 0F
    private var grayBrightness = 0F
    private var colorSaturation = 0F
    private var mInitColor:Int = -1
    var parentView:GraySeekBar?= null

    constructor(context: Context?) : super(context)
    constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)

        val height = MeasureSpec.getSize(heightMeasureSpec)
        val heightMode = MeasureSpec.getMode(heightMeasureSpec)

        val realHeight = if (heightMode == MeasureSpec.EXACTLY){
            height
        }else{
            context.dip(30F).toInt()
        }
        setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), realHeight)
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        val centreX:Float = h*1F/2
        externalRect.set(paddingStart.toFloat(), centreX - externalHeight,
                (w - paddingEnd).toFloat(), centreX + externalHeight)
        val d = externalHeight - innerHeight
        innerRect.set(paddingStart.toFloat() + d, centreX - innerHeight,
                (w - paddingEnd - d), centreX + innerHeight)
        setColor(mInitColor,mHSV[1],mHSV[2])
        parentView?.callback()
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        canvas?.apply {
            drawRoundRect(externalRect, externalHeight, externalHeight, externalPaint)
            drawRoundRect(innerRect, innerHeight, innerHeight, innerPaint)
        }
    }

    fun setColor(@ColorInt color: Int,saturation:Float,brightness:Float){
        mHSV[1] = saturation
        mHSV[2] = brightness
        if (width > 0 && height > 0) {
            grayBrightness = brightness
            val g = rgbToGray(color, brightness)
            val colors = intArrayOf(color, g)
            val red = color shr 16 and 0xFF
            val green = (color shr 8) and 0xFF
            val blue = color and 0xFF
            val hsv = FloatArray(3)
            Color.RGBToHSV(red, green, blue, hsv)
            innerPaint.shader = LinearGradient(
                innerRect.left, innerRect.height(), innerRect.right,
                innerRect.height(), colors, null, Shader.TileMode.REPEAT
            )
            invalidate()
        }else{
            mInitColor = color
        }
    }

    fun getColor(x:Float):Int{
        val ratio = max(0F,min(x,width.toFloat()))/width
        mHSV[1] = colorSaturation*(1-ratio)
        mHSV[2] = colorBrightness + (grayBrightness - colorBrightness)*ratio
        return Color.HSVToColor(mHSV)
    }

    private fun rgbToGray(@ColorInt color: Int,brightness: Float):Int{
        val red = color shr 16 and 0xFF
        val green = (color shr 8) and 0xFF
        val blue = color and 0xFF
        val hsv = FloatArray(3)
        Color.RGBToHSV(red,green,blue,hsv)
        mHSV[0] = hsv[0]
        colorSaturation = hsv[1]
        hsv[1] = 0F
        colorBrightness = hsv[2]
        hsv[2] = brightness
        return Color.HSVToColor(hsv)
    }

}
